package com.nav.util;

import java.util.ArrayList;
import java.util.List;

public class XMLParser {
	int i;
	char c[];
	public List<XMLNode> parseBody(String s) {
		i = 0;
		c = s.toCharArray();
		return parseBody();
	}
	private List<XMLNode> parseBody() {
		List<XMLNode> l = new ArrayList<XMLNode>();
		try {
			while(i < c.length) {
				while(Character.isSpaceChar(c[i]))
					i++;
				StringBuilder value = new StringBuilder();
				// considering end of input as end of value
				while(i < c.length && c[i] != '<')
					value.append(c[i++]);
				if(value.length() > 0) {
					XMLNode text = new XMLNode(XMLNode.TAG_TEXT);
					text.attr.put(XMLNode.ATTR_VALUE, value.toString());
					l.add(text);
				}
				int j = i;
				while(Character.isSpaceChar(c[++j]));
				if(c[j] == '/')
					break;
				l.add(parseTag());
			}
		} catch(Exception e) {
			// expecting only ArrayIndexOutOfBoundsException, therefore ignoring
		}
		return l;
	}
	private XMLNode parseTag() {
		assert(c[i] == '<');
		while(Character.isSpaceChar(c[++i]));
		StringBuilder tagName = new StringBuilder();
		// considering end of input as end of tag name
		while(i < c.length && !Character.isSpaceChar(c[i]) && c[i] != '>')
			tagName.append(c[i++]);
		XMLNode tag = new XMLNode(tagName.toString());
		try {
			while(Character.isSpaceChar(c[i]))
				i++;
			// TODO: handle self closing tags like <br/> and tags that do not need close tags like <br> etc
			while(c[i] != '>') {
				StringBuilder attrName = new StringBuilder(), attrValue = new StringBuilder();
				// considering end of input as end of attribute name
				while(i < c.length && !Character.isSpaceChar(c[i]) && c[i] != '=' && c[i] != '>')
					attrName.append(c[i++]);
				try {
					while(Character.isSpaceChar(c[i]))
						i++;
					if(c[i] == '=') {
						while(Character.isSpaceChar(c[++i]));
						if(c[i] == '"') {
							while(c[++i] != '"') {
								if(c[i] == '\\')
									attrValue.append(c[++i]);
								else
									attrValue.append(c[i]);
							}
							i++;
						} else if(c[i] == '\'') {
							while(c[++i] != '\'') {
								if(c[i] == '\\')
									attrValue.append(c[++i]);
								else
									attrValue.append(c[i]);
							}
							i++;
						} else {
							while(!Character.isSpaceChar(c[i]) && c[i] != '>')
								attrValue.append(c[i++]);
						}
						while(Character.isSpaceChar(c[i]))
							i++;
					}
				} catch(Exception e) {
					// expecting only ArrayIndexOutOfBoundsException, therefore ignoring
				}
				tag.attr.put(attrName.toString(), attrValue.toString().trim());
			}
			i++;
			tag.body = parseBody();
			int j = i;
			assert(c[j] == '<');
			while(Character.isSpaceChar(c[++j]));
			assert(c[j] == '/');
			while(Character.isSpaceChar(c[++j]));
			StringBuilder endTagName = new StringBuilder();
			while(!Character.isSpaceChar(c[j]) && c[j] != '>')
				endTagName.append(c[j++]);
			if(!endTagName.toString().equals(tagName.toString()))
				return tag;
			while(Character.isSpaceChar(c[j]))
				j++;
			assert(c[j] == '>');
			i = j + 1;
		} catch(Exception e) {
			// expecting only ArrayIndexOutOfBoundsException, therefore ignoring
		}
		return tag;
	}
}
